/*
 * @Author: wangcb
 * @Email: wangcbgg@163.com
 * @Date: 2021-08-28 16:15:13
 * @LastEditTime: 2021-12-31 17:16:54
 * 文字滚动marquee
 */
import { DIR } from "../constant";
import cancelAFrame from "../helpers/cancelAFrame";
import extentDOM from "../helpers/extentDOM";
import requestAFrame from "../helpers/requestAFrame";
import { supportCss3 } from "../helpers/util";
/**
 * Marquee类
 * @class Marquee
 */
class Marquee {
    constructor(config) {
        /**
         * 动画帧id
         * @private
         */
        this.requestId = 0;
        /**
         * shadow添加timer
         * @private
         */
        this.timer = 0;
        /**
         * 当前状态
         * @private
         */
        this.status = 'stop';
        /**
         * 滚动文字间的像素间距
         * @default 50
         */
        this.space = 50;
        /**
         * 延迟滚动毫秒数
         * @default 1000
         */
        this.delay = 1000;
        /**
         * 滚动方向
         * @type {TKeyDir}
         * @default 'left'
         */
        this.direction = DIR.LEFT;
        /**
         * 速度
         * @type {number}
         * @default 10
         */
        this.speed = 10;
        /**
         * 是否显示渐隐效果
         * @type {boolean}
         * @default true
         */
        this.shadow = true;
        /**
         * 是否强制js执行
         * @type {boolean}
         */
        this.forceJs = false;
        /**
         * 是否是维语文字
         * @type {boolean}
         */
        this.wy = false;
        /**
         * 持有的dom元素
         * @type {ExtendHTMLElement | null}
         */
        this.element = null;
        /**
         * element中的原始内容
         * @type {string}
         * @default '''
         */
        this.content = '';
        this.requestId = 0;
        this.update(config);
        this.$init();
    }
    /**
     * 初始化样式
     * @private
     */
    $init() {
        const head = document.getElementsByTagName('head')[0];
        const marqueeId = '-marquee-id-';
        if (!document.getElementById(marqueeId)) {
            const style = document.createElement('style');
            style.type = 'text/css', style.id = marqueeId;
            const css = '@-webkit-keyframes marquee-left-animate-timestamp{0%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}100%{-webkit-transform:translate3d(-50%,0,0);transform:translate3d(-50%,0,0)}}@keyframes marquee-left-animate-timestamp{0%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}100%{-webkit-transform:translate3d(-50%,0,0);transform:translate3d(-50%,0,0)}}@-webkit-keyframes marquee-right-animate-timestamp{0%{-webkit-transform:translate3d(-50%,0,0);transform:translate3d(-50%,0,0)}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}@keyframes marquee-right-animate-timestamp{0%{-webkit-transform:translate3d(-50%,0,0);transform:translate3d(-50%,0,0)}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}@-webkit-keyframes marquee-right-wy-animate-timestamp{0%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}100%{-webkit-transform:translate3d(50%,0,0);transform:translate3d(50%,0,0)}}@keyframes marquee-right-wy-animate-timestamp{0%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}100%{-webkit-transform:translate3d(50%,0,0);transform:translate3d(50%,0,0)}}@-webkit-keyframes marquee-up-animate-timestamp{0%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}100%{-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}}@keyframes marquee-up-animate-timestamp{0%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}100%{-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}}@-webkit-keyframes marquee-down-animate-timestamp{0%{-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}@keyframes marquee-down-animate-timestamp{0%{-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.marquee-left-timestamp{-webkit-animation:marquee-left-animate-timestamp 5s linear infinite;animation:marquee-left-animate-timestamp 5s linear infinite}.marquee-right-timestamp{-webkit-animation:marquee-right-animate-timestamp 5s linear infinite;animation:marquee-right-animate-timestamp 5s linear infinite}.marquee-right-wy-timestamp{-webkit-animation:marquee-right-wy-animate-timestamp 5s linear infinite;animation:marquee-right-wy-animate-timestamp 5s linear infinite}.marquee-up-timestamp{-webkit-animation:marquee-up-animate-timestamp 5s linear infinite;animation:marquee-up-animate-timestamp 5s linear infinite}.marquee-down-timestamp{-webkit-animation:marquee-down-animate-timestamp 5s linear infinite;animation:marquee-down-animate-timestamp 5s linear infinite}.marquee-shadow-h-timestamp{-webkit-mask:linear-gradient(to right,transparent 0,#000 10%,#000 90%,transparent 100%);mask:linear-gradient(to right,transparent 0,#000 10%,#000 90%,transparent 100%)}.marquee-shadow-v-timestamp{-webkit-mask:linear-gradient(to bottom,transparent 0,#000 10%,#000 90%,transparent 100%);mask:linear-gradient(to bottom,transparent 0,#000 10%,#000 90%,transparent 100%)}.nowrap-timestamp{white-space:nowrap}.hidden-timestamp{overflow:hidden}';
            if ('styleSheet' in style) { // @ts-ignore IE适配
                style.setAttribute('type', 'text/css'); // @ts-ignore IE适配
                style.styleSheet.cssText = css.replace(/timestamp/g, '' + Marquee.timestamp);
            }
            else {
                // 避免样式类名冲突
                style.innerHTML = css.replace(/timestamp/g, '' + Marquee.timestamp);
            }
            head.appendChild(style);
        }
    }
    /**
     * 更新配置
     * @param config 文字滚动配置
     */
    update(config) {
        this.stop();
        this.status = 'stop';
        if (config) {
            if (config.space)
                this.space = config.space;
            if (config.delay)
                this.delay = config.delay;
            if (config.direction)
                this.direction = config.direction;
            if (config.speed)
                this.speed = config.speed;
            if (typeof config.shadow === 'boolean')
                this.shadow = config.shadow;
            if (typeof config.forceJs === 'boolean')
                this.forceJs = config.forceJs;
            if (typeof config.wy === 'boolean')
                this.wy = config.wy;
            if (config.element)
                this.element = config.element;
        }
        return this;
    }
    /**
     * 开始滚动
     */
    move() {
        if (this.status !== 'move') {
            this.status = 'move';
            const ele = this.element;
            if (!ele)
                return;
            const className = this.wy ? `marquee-${this.direction}-wy-${Marquee.timestamp}` : `marquee-${this.direction}-${Marquee.timestamp}`;
            if (ele.firstElementChild?.classList?.contains(className))
                return;
            this.content = ele.innerHTML;
            if (this.content && this.content !== '') { // 有内容
                const scroller = document.createElement('div'); // 滚动容器
                extentDOM(scroller);
                const animate = (animateTime) => {
                    scroller.className = className;
                    scroller.style.webkitAnimationDuration = `${animateTime}ms`;
                    scroller.style.animationDuration = `${animateTime}ms`;
                };
                if (this.direction === DIR.UP || this.direction === DIR.DOWN) {
                    this.timer = setTimeout(() => {
                        if (ele.scrollHeight > ele.clientHeight) { // 内容超出
                            const hidden = ` hidden-${Marquee.timestamp}`;
                            if (ele.className.indexOf(hidden) === -1)
                                ele.className += hidden;
                            // shadow
                            const shadow = ` marquee-shadow-v-${Marquee.timestamp}`;
                            if (supportCss3('transform'))
                                if (this.shadow && ele.className.indexOf(shadow) === -1)
                                    ele.className += shadow;
                            const styleAttr = `style="margin:0;padding-bottom:${this.space}px"`;
                            scroller.innerHTML = `<div ${styleAttr}>${this.content}</div><div ${styleAttr}>${this.content}</div>`;
                            ele.innerHTML = '', ele.appendChild(scroller);
                            if (supportCss3('transform') && !this.forceJs) {
                                scroller.style.height = `${scroller.scrollHeight / 2}px`;
                                // 按文本宽度调整速度
                                const animateTime = Math.floor(scroller.scrollHeight * Math.abs(200 / this.speed));
                                animate(animateTime);
                            }
                            else {
                                scroller.style.position = 'absolute';
                                const render = () => {
                                    let cur = parseInt(scroller.style.top, 10);
                                    if (this.direction === DIR.UP) {
                                        if (Math.abs(cur) <= scroller.offsetHeight + this.space)
                                            scroller.style.top = `${cur - (this.speed / 40)}px`;
                                        else
                                            scroller.style.top = `${ele.clientHeight}px`;
                                    }
                                    else {
                                        if (cur <= ele.clientHeight)
                                            scroller.style.top = `${cur + (this.speed / 40)}px`;
                                        else
                                            scroller.style.top = `${-scroller.offsetHeight}px`;
                                    }
                                    this.requestId = requestAFrame(render);
                                };
                                render();
                            }
                        }
                    }, this.delay);
                }
                else {
                    const space = extentDOM(ele).getStyle('white-space');
                    if (space !== 'nowrap') {
                        const nowrap = ` nowrap-${Marquee.timestamp}`;
                        if (ele.className.indexOf(nowrap) === -1)
                            ele.className += nowrap;
                    }
                    this.timer = setTimeout(() => {
                        const shadow = ` marquee-shadow-h-${Marquee.timestamp}`;
                        if (ele.scrollWidth > ele.clientWidth) { // 内容超出
                            const hidden = ` hidden-${Marquee.timestamp}`;
                            if (ele.className.indexOf(hidden) === -1)
                                ele.className += hidden;
                            // shadow
                            if (supportCss3('transform'))
                                if (this.shadow && ele.className.indexOf(shadow) === -1)
                                    ele.className += shadow;
                            const float = this.wy ? this.direction : 'left';
                            if (supportCss3('transform') && !this.forceJs) {
                                scroller.style.cssText = `float:${float};line-height:inherit`;
                            }
                            else {
                                scroller.style.cssText = `float:${float};line-height:inherit;position:relative;left:0`;
                            }
                            const padding = this.wy ? this.direction === 'left' ? 'right' : 'left' : 'right';
                            const styleAttr = `style="padding-${padding}:${this.space}px;line-height:inherit;font-style:normal"`;
                            scroller.innerHTML = `<i ${styleAttr}>${this.content}</i><i ${styleAttr}>${this.content}</i>`;
                            ele.innerHTML = '', ele.appendChild(scroller);
                            if (supportCss3('transform') && !this.forceJs) {
                                // 按文本宽度调整速度
                                const animateTime = Math.floor(scroller.offsetWidth * Math.abs(100 / this.speed));
                                animate(animateTime);
                            }
                            else {
                                const render = () => {
                                    let cur = parseInt(scroller.style.left, 10);
                                    if (this.direction === DIR.LEFT) {
                                        if (Math.abs(cur) <= scroller.offsetWidth - this.space)
                                            scroller.style.left = `${cur - (this.speed / 10)}px`;
                                        else
                                            scroller.style.left = `${ele.clientWidth}px`;
                                    }
                                    else {
                                        if (cur <= ele.clientWidth)
                                            scroller.style.left = `${cur + (this.speed / 10)}px`;
                                        else
                                            scroller.style.left = `${-scroller.offsetWidth}px`;
                                    }
                                    this.requestId = requestAFrame(render);
                                };
                                render();
                            }
                        }
                    }, this.delay);
                }
            }
        }
    }
    /**
     * 停止滚动
     */
    stop() {
        if (this.status !== 'stop') {
            this.status = 'stop';
            const ele = this.element;
            if (!ele)
                return;
            const nowrap = ` nowrap-${Marquee.timestamp}`;
            if (ele.className.indexOf(nowrap) !== -1)
                ele.className = ele.className.replace(nowrap, '');
            if (supportCss3('transform')) {
                if (this.timer)
                    clearTimeout(this.timer), this.timer = 0;
                const shadow_h = ` marquee-shadow-h-${Marquee.timestamp}`, shadow_v = ` marquee-shadow-v-${Marquee.timestamp}`;
                if (this.shadow && ele.className.indexOf(shadow_h) !== -1)
                    ele.className = ele.className.replace(shadow_h, '');
                if (this.shadow && ele.className.indexOf(shadow_v) !== -1)
                    ele.className = ele.className.replace(shadow_v, '');
            }
            else {
                if (this.requestId)
                    cancelAFrame(this.requestId);
            }
            if (this.content && this.content !== '')
                ele.innerHTML = this.content;
        }
    }
}
/**
 * 当前时间戳
 * @static
 * @private
 */
Marquee.timestamp = Date.now();
/**
 * 文字滚动配置定义
 * @typedef IMarqueeConfig
 * @property {number} [space] 滚动文字间的像素间距
 * @property {number} [delay] 延迟滚动毫秒数
 * @property {TKeyDir} [direction] 滚动方向 'left' | 'right'
 * @property {number} [speed] 速度
 * @property {boolean} [shadow] 是否显示左右渐隐效果
 * @property {boolean} [forceJs] 是否强制js执行
 * @property {boolean} [wy] 是否是维语文字
 * @property {ExtendHTMLElement} element 持有的dom元素
 */
/**
 * 生成文字滚动实例
 * @param {IMarqueeConfig} config 文字滚动配置
 * @example
 * const dom = $('area0_list_0');
 * const marqueeObj = createMarquee({ element: dom });
 * marqueeObj.move();// 开始滚动
 * marqueeObj.stop();// 停止滚动
 */
export function createMarquee(config) {
    return new Marquee(config);
}
